#include "data.hpp"

Data::Data()
{
    this->_Filename=(char*)"fast_2D_0.dat";
    this->_xvizPath=QDir::homePath()+"/.XViz";
}

Data::~Data()
{
    delete this->_Filename;
}

void Data::setFileName(char* Filename)
{
    this->_Filename = Filename;
}

char* Data::getFileName()
{
    return this->_Filename;
}

void Data::ReadData()
{
    ifstream inFile(this->_Filename, ifstream::in);
    int Index=0; // aktualny numer linii
    string Line;
    QString Line2Add;
    QString LineTemp;

    if(inFile.is_open()){
        while(getline(inFile, Line)){
            LineTemp = QString::fromStdString(Line).remove("\r");
            QStringList ns = LineTemp.split(QRegExp("\\s+"));
            if(ns.count()==2)
                Line2Add=ns[0]+"   "+ns[1];
            else if(ns.count()==3)
                Line2Add=ns[0]+"   "+ns[1]+"   "+ns[2];
            else if(ns.count()==0)
                Line2Add=ns[0];
            else
                for(int i=0; i<ns.count();++i)
                    Line2Add+=ns[i]+" ";
            _DataSet.push_back(Line2Add.toAscii().data());
            ++Index;
            Line2Add.clear();
        }
    }
    this->_NumLines=Index;
    inFile.close();
}

void Data::SplitData()
{
    Set TempSet;
    vector<Set> TempSplitted;

    for(int i=1; i<=this->_NumLines; ++i)
    {
        if(this->_DataSet[i][0]=='#')
            TempSet._Top.push_back(this->_DataSet[i]);
        else if(this->_DataSet[i]=="\r" || i==this->_NumLines-1 ||
                this->_DataSet[i]=="\0" || this->_DataSet[i]=="\n" ||
                this->_DataSet[i]=="  " || this->_DataSet[i]==" ")
        {
            if(i==_NumLines-1)
                TempSet._Data.push_back(this->_DataSet[i]);
            TempSplitted.push_back(TempSet);
            i++;
            TempSet._Top.clear();
            TempSet._Data.clear();
        }
        else
            TempSet._Data.push_back(this->_DataSet[i]);
    }
    this->_DataSplitted=TempSplitted;
}

void Data::generateDataFile(vector<int> Sets)
{
    ofstream outFile((this->_xvizPath+"/data.xviz").toAscii().data(), ofstream::out);
    outFile<<"# Plik wygenerowany automatycznie przez XViz dla gnuplota.\n";
    outFile<<"# Ilosc zbiorow danych: "<<Sets.size()<<"\n";
    for(unsigned int set=0; set<Sets.size(); ++set)
    {
        for(unsigned int j=0; j<this->_DataSplitted[Sets[set]]._Top.size(); ++j)
            outFile<<this->_DataSplitted[Sets[set]]._Top[j]<<"\n";
        for(unsigned int j=0; j<this->_DataSplitted[Sets[set]]._Data.size(); ++j)
            outFile<<this->_DataSplitted[Sets[set]]._Data[j]<<"\n";
        outFile<<"\n\n";
    }

    //obrobione zbiory danych
    for(unsigned int i=0; i<this->_DataProcessed.size(); ++i)
    {
        for(unsigned int j=0; j<this->_DataProcessed[i]._Top.size(); ++j)
            outFile<<this->_DataProcessed[i]._Top[j]<<"\n";
        for(unsigned int j=0; j<this->_DataProcessed[i]._Data.size(); ++j)
            outFile<<this->_DataProcessed[i]._Data[j]<<"\n";
        outFile<<"\n\n";
    }
    outFile.close();
}

void Data::generateScriptFile(BibStyle *bs, vector<Graph*> ListOfCharts, Labels* labels)
{
    ofstream outFile((this->_xvizPath+"/plot.gplt").toAscii().data(), ofstream::out);

    if(labels->_Output == "postscript eps" ||
       labels->_Output == "latex"){
        outFile<<"set terminal "<<labels->_Output<<" enh \'Helvetica\' 35\n";
        outFile<<"set output \""<<labels->_OutputFileName<<"\"\n";
        outFile<<"set size 2,2\n";
    }
    else
        outFile<<"set terminal "<<labels->_Output<<"\n";

    outFile<<"set title \""<<labels->_Title<<"\"\n";
    outFile<<"set xlabel \""<<labels->_xLabel<<"\"\n";
    outFile<<"set ylabel \""<<labels->_yLabel<<"\"\n";
    outFile<<"set zlabel \""<<labels->_zLabel<<"\"\n";

    for(unsigned int i=0; i<ListOfCharts.size(); ++i)
    {
        int IDStyle = ListOfCharts.at(i)->getStyle()-1;;
        if(bs->_styles.size()==0)
            outFile<<"set style line "<<i+1<<" lt 1 lc 1 lw 1 pt 1 ps 1 pi 1\n";
        else
            outFile<<"set style line "<<i+1<<
                    " lt "<<bs->_styles[IDStyle]->_LineType<<
                    " lc "<<bs->_styles[IDStyle]->_LineColor<<
                    " lw "<<bs->_styles[IDStyle]->_LineWidth<<
                    " pt "<<bs->_styles[IDStyle]->_PointType<<
                    " ps "<<bs->_styles[IDStyle]->_PointSize<<
                    " pi "<<bs->_styles[IDStyle]->_PointInterval<<
                    "\n";

    }
    for(unsigned int i=0; i<labels->_Labels.size(); ++i)
    {
        outFile<<"set label \'"<<labels->_Labels[i]._text<<"\' at "<<
                labels->_Labels[i]._x<<","<<
                labels->_Labels[i]._y<<"\n";
    }


    if(labels->_xMin!="Auto")
        outFile<<"set xrange ["<<labels->_xMin<<":"<<
                labels->_xMax<<"]\n";
    if(labels->_yMin!="Auto")
        outFile<<"set yrange ["<<labels->_yMin<<":"<<
                labels->_yMax<<"]\n";
    if(ListOfCharts.at(0)->getSize()==3)
        if(labels->_zMin!="Auto")
            outFile<<"set xrange ["<<labels->_zMin<<","<<
                    labels->_zMax<<"]\n";

    if(ListOfCharts.at(0)->getSize()==3)
    {
        outFile<<"set dgrid3d 15,15\n";
        outFile<<"set hidden3d\n";
        outFile<<"splot";

        for(unsigned int i=0; i<ListOfCharts.size(); ++i){
            if(ListOfCharts[i]->getifLine() == 1){
                outFile<<"\""<<(this->_xvizPath+"/data.xviz").toAscii().data()<<"\" index "<<i<<" w l ls "<<i+1;
                if(i<ListOfCharts.size()-1)
                    outFile<<", ";
                else
                    outFile<<"\n";
            }
            else{
                outFile<<"\""<<(this->_xvizPath+"/data.xviz").toAscii().data()<<"\" index "<<i<<" ls "<<i+1;
                if(i<ListOfCharts.size()-1)
                    outFile<<", ";
                else
                    outFile<<"\n";
            }
        }
    }
    else
    {
        outFile<<"plot ";
        for(unsigned int i=0; i<ListOfCharts.size(); ++i){
            if(ListOfCharts[i]->getifLine() == 1){
                outFile<<"\""<<(this->_xvizPath+"/data.xviz").toAscii().data()<<"\" index "<<i<<" w l ls "<<i+1;
                if(i<ListOfCharts.size()-1)
                    outFile<<", ";
                else
                    outFile<<"\n";
            }
            else{
                outFile<<"\""<<(this->_xvizPath+"/data.xviz").toAscii().data()<<"\" index "<<i<<" ls "<<i+1;
                if(i<ListOfCharts.size()-1)
                    outFile<<", ";
                else
                    outFile<<"\n";
            }
        }

    }
    outFile.close();
}

vector< vector<float> > Data::convVecStr2TabFloat(vector<string> DataSet)
{
    vector< vector<float> > temp;
    vector<float> pom;
    QStringList ns;
    QString str;
    for(unsigned int i=0; i<DataSet.size(); ++i)
    {
        str = QString::fromStdString(DataSet[i]);
        ns = str.split("   ");
        if(ns.count()<3){
            pom.push_back(ns.at(0).toFloat());
            pom.push_back(ns.at(1).toFloat());
            temp.push_back(pom);
        }
        ns.clear();
        pom.clear();
    }
    return temp;
}

vector<float> Data::linearRegression(vector<string> Set)
{
    vector<float> toReturn;
    vector< vector<float> > temp;
    temp = this->convVecStr2TabFloat(Set);

    float a=0, b=0;
    unsigned int n = temp.size();

    float apart1=0, apart2=0, apart3=0, apart4=0;

    for(unsigned int i=0; i<n; ++i)
    {
        //cout<< temp[i][0]<<" "<<temp[i][1]<<endl;
        apart1 += temp[i][0]*temp[i][1]; //sum{x_iy_i}
        apart2 += temp[i][0]; //sum{x_i}
        apart3 += temp[i][1]; //sum{y_i}
        apart4 += temp[i][0]*temp[i][0]; //sum{x_i^2}
    }
    a=(n * apart1 - apart2 * apart3) / (n * apart4 - (apart2 * apart2));
    b=(apart3 - a * apart2) / n;

    toReturn.push_back(a);
    toReturn.push_back(b);

    return toReturn;
}

vector<float> Data::quadraticRegression(vector<string> Set)
{
    vector<float> toReturn;
    vector< vector<float> > temp;
    temp = this->convVecStr2TabFloat(Set);

    float a=0, b=0, c=0;
    unsigned int n = temp.size();

    float sumx4=0, sumx3=0, sumx2=0, sumx=0;
    float sumx2y=0, sumxy=0, sumy=0;

    for(unsigned int i=0; i<n; ++i)
    {
        float pom = temp[i][0];
        sumx4 += pom*pom*pom*pom;
        sumx3 += pom*pom*pom;
        sumx2 += pom*pom;
        sumx += pom;
        sumx2y += pom*pom*temp[i][1];
        sumxy += pom*temp[i][1];
        sumy += temp[i][1];
    }

    QMatrix4x4 CMatrix = QMatrix4x4::QMatrix4x4(sumx4,sumx3,sumx2,0,
                                                sumx3,sumx2,sumx,0,
                                                sumx2,sumx,n,0,
                                                0,0,0,1);
    QMatrix4x4 invCMatrix = CMatrix.inverted();
    QVector4D row1 = invCMatrix.row(0);
    QVector4D row2 = invCMatrix.row(1);
    QVector4D row3 = invCMatrix.row(2);
    a=row1.x()*sumx2y+row1.y()*sumxy+row1.z()*sumy;
    b=row2.x()*sumx2y+row2.y()*sumxy+row2.z()*sumy;
    c=row3.x()*sumx2y+row3.y()*sumxy+row3.z()*sumy;

    toReturn.push_back(a);
    toReturn.push_back(b);
    toReturn.push_back(c);

    return toReturn;
}

int Data::numOfCols(int ID)
{
    QString str = QString::fromStdString(this->_DataSplitted[ID]._Data[0]);
    QStringList ns = str.split("   ");
    return ns.count();

}

int Data::numOfRows(int ID)
{
    return this->_DataSplitted[ID]._Data.size();
}

double Data::minInCol(int ID, int ColNum)
{
    QString temp;
    QString temp2 = QString::fromStdString(this->_DataSplitted[ID]._Data[0]);
    QStringList tempMin = temp2.split("   ");
    for(unsigned int i=1; i<this->_DataSplitted[ID]._Data.size(); ++i)
    {
        temp = QString::fromStdString(this->_DataSplitted[ID]._Data[i]);
        QStringList ns = temp.split("   ");
        if(ns.at(ColNum).toDouble() < tempMin.at(ColNum).toDouble())
            tempMin = ns;
    }
    return tempMin.at(ColNum).toDouble();
}

double Data::maxInCol(int ID, int ColNum)
{
    QString temp;
    QString temp2 = QString::fromStdString(this->_DataSplitted[ID]._Data[0]);
    QStringList tempMax = temp2.split("   ");
    for(unsigned int i=1; i<this->_DataSplitted[ID]._Data.size(); ++i)
    {
        temp = QString::fromStdString(this->_DataSplitted[ID]._Data[i]);
        QStringList ns = temp.split("   ");
        if(ns.at(ColNum).toDouble() > tempMax.at(ColNum).toDouble())
            tempMax = ns;
    }
    return tempMax.at(ColNum).toDouble();
}
